/**
 * @file UserRuptureSprgbm.cpp
 * @brief User subroutine to determine rupture of spot welds (SPRGBM elements)
 * 
 * This subroutine is called for all SPRGBM elements using a rupture model with option 3.
 * It evaluates whether a spot weld should rupture based on applied forces.
 */

#include <cmath>
#include <algorithm>
#include <iostream>
#include <array>

// Define real type based on precision
#ifdef DOUBLE_PRECISION
using Real = double;
#else 
using Real = float;
#endif

/**
 * @brief Determines if a spot weld element should rupture
 * 
 * @param elementId User ID of the SPRGBM element
 * @param currentTime Simulation time up to now
 * @param timeStep Current time step (0.0 when cycle = 0)
 * @param cycle Current cycle number (starts from 0)
 * @param forces SPRGBM force/moment vector in local beam system (6 components)
 * @param velocities SPRGBM velocity vector in local beam system (6 components)
 * @param node1Coords Coordinates of SPRGBM node 1 (3 components)
 * @param node2Coords Coordinates of SPRGBM node 2 (3 components)
 * @param userParams Parameters from RUPMO input (18 values)
 * @return Real Failure indicator (>= 1.0 indicates failure, < 1.0 no failure)
 */
Real UserRuptureSprgbm(
    int elementId,
    Real currentTime,
    Real timeStep,
    int cycle,
    const std::array<Real, 6>& forces,
    const std::array<Real, 6>& velocities,
    const std::array<Real, 3>& node1Coords,
    const std::array<Real, 3>& node2Coords,
    const std::array<Real, 18>& userParams)
{
    // Output failure indicator
    Real failureIndicator = 0.0;
    
    // Extract rupture criterion parameter
    // USERPAR(1) comes from input card columns 9-16 (format E8.0)
    Real maxAllowedForce = userParams[0];

    // Calculate maximum absolute force component (Fx, Fy, Fz)
    Real maxAppliedForce = std::max({std::abs(forces[0]), 
                                   std::abs(forces[1]), 
                                   std::abs(forces[2])});

    // Apply rupture criterion:
    // If maximum force exceeds threshold, mark as failed
    // failureIndicator >= 1.0 indicates rupture
    // failureIndicator < 1.0 indicates no rupture
    if (maxAppliedForce > maxAllowedForce) {
        failureIndicator = 1.1; // Value > 1.0 indicates failure
        
        // Print rupture message
        std::cout << "SPRGBM " << elementId << " USERRUPTURE FAILED" << std::endl;
    }
    else {
        failureIndicator = 0.0; // Value < 1.0 indicates no failure
    }

    return failureIndicator;
}

/**
 * @brief Example usage of the spot weld rupture function
 */
void ExampleUsage()
{
    // Example input data
    int elementId = 12345;
    Real currentTime = 0.1;
    Real timeStep = 0.001;
    int cycle = 100;
    
    std::array<Real, 6> forces = {1000.0, 500.0, 800.0, 0.0, 0.0, 0.0};
    std::array<Real, 6> velocities = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
    std::array<Real, 3> node1Coords = {0.0, 0.0, 0.0};
    std::array<Real, 3> node2Coords = {1.0, 0.0, 0.0};
    
    // User parameters (typically from input deck)
    // First parameter (userParams[0]) is the force threshold
    std::array<Real, 18> userParams = {900.0}; // Only first parameter used in this example
    
    // Call rupture function
    Real result = UserRuptureSprgbm(
        elementId,
        currentTime,
        timeStep,
        cycle,
        forces,
        velocities,
        node1Coords,
        node2Coords,
        userParams);
    
    // Check result
    if (result >= 1.0) {
        std::cout << "Element " << elementId << " has ruptured!" << std::endl;
    }
}